import { TaskExecutor } from './TaskExecutor';
import {
    QueueStats,
    ResultQuery,
    Task,
    TaskEvent,
    TaskExecuteOption,
    TaskPriority,
    TaskQuery,
    TaskResult,
    TaskStatus,
} from './types';

// 任务查询服务 - 负责任务状态和结果的查询
const initialStats: QueueStats = {
    pending: 0,
    running: 0,
    completed: 0,
    failed: 0,
    cancelled: 0,
    totalProcessed: 0,
    averageExecutionTime: 0,
    cacheHitRate: 0,
};
export class TaskQueryService<T = any> {
    private taskHistory: Map<string, Task> = new Map();
    private resultHistory: Map<string, TaskResult> = new Map();
    private resultsByName: Map<string, TaskResult[]> = new Map();
    private stats: QueueStats = initialStats;

    constructor(private executor: TaskExecutor) {
        this.setupEventListeners();
    }

    /**
     * 查询任务信息
     */
    public queryTasks(query: TaskQuery = {}): Task[] {
        const { pending, running } = this.executor.getQueueSnapshot();
        const allTasks = [...pending, ...running, ...Array.from(this.taskHistory.values())];

        return allTasks.filter((task) => this.matchesTaskQuery(task, query));
    }

    /**
     * 查询任务结果
     */
    public queryResults<R = T>(query: ResultQuery = {}): TaskResult<R>[] {
        const allResults = Array.from(this.resultHistory.values());
        return allResults.filter((result) => this.matchesResultQuery(result, query));
    }

    /**
     * 等待任务完成（通过任务ID）
     */
    public async waitForTask<R = T>(
        taskId: string,
        option: TaskExecuteOption = {
            immediate: false,
        }
    ): Promise<TaskResult<R>> {
        // 先检查是否已经有结果
        const existingResult = this.queryResults<R>({ taskId });
        if (existingResult.length > 0) {
            return existingResult[0];
        }
        if (option.immediate) {
            this.executor.executeImmediately(taskId);
        }

        return new Promise((resolve, reject) => {
            // 监听任务完成
            const onCompleted = (event: TaskEvent) => {
                if (event.task.id === taskId && event.result) {
                    this.executor.removeEventListener('taskCompleted', onCompleted);
                    resolve(event.result);
                }
            };
            const onFailed = (event: TaskEvent) => {
                if (event.task.id === taskId) {
                    this.executor.removeEventListener('taskFailed', onFailed);
                    reject(event.task.error || new Error(`Task ${taskId} failed`));
                }
            };
            const onCancelled = (event: TaskEvent) => {
                if (event.task.id === taskId) {
                    this.executor.removeEventListener('taskCancelled', onCancelled);
                    reject(new Error(`Task ${taskId} was cancelled`));
                }
            };

            this.executor.addEventListener('taskCompleted', onCompleted);
            this.executor.addEventListener('taskFailed', onFailed);
            this.executor.addEventListener('taskCancelled', onCancelled);
        });
    }

    public async waitForTaskByName<R = T>(
        taskName: string,
        option: TaskExecuteOption = {
            immediate: false,
        }
    ): Promise<TaskResult<R>[]> {
        const tasks = this.queryTasks({ name: taskName });
        return Promise.all(tasks.map((task) => this.waitForTask<R>(task.id, option)));
    }

    /**
     * 等待所有任务完成
     */
    public async waitForAllTasks(): Promise<void> {
        const { pending, running } = this.executor.getQueueSnapshot();
        if (pending.length === 0 && running.length === 0) {
            return;
        }

        return new Promise((resolve) => {
            const onQueueEmpty = () => {
                resolve();
                this.executor.removeEventListener('queueEmpty', onQueueEmpty);
            };
            this.executor.addEventListener('queueEmpty', onQueueEmpty);
        });
    }

    public destroy(): void {
        this.taskHistory.clear();
        this.resultHistory.clear();
        this.resultsByName.clear();
        this.stats = initialStats;
        this.executor.removeEventListener('taskCompleted', this.handleTaskCompleted);
        this.executor.removeEventListener('taskFailed', this.handleTaskFailed);
        this.executor.removeEventListener('taskCancelled', this.handleTaskCancelled);
    }

    /**
     * 获取统计信息
     */
    public getStats(): Readonly<QueueStats> {
        const { pending, running } = this.executor.getQueueSnapshot();

        return {
            ...this.stats,
            pending: pending.length,
            running: running.length,
        };
    }

    /**
     * 获取执行时间统计
     */
    public getExecutionTimeStats(): {
        average: number;
        min: number;
        max: number;
        median: number;
        p95: number;
        total: number;
        count: number;
    } {
        const results = Array.from(this.resultHistory.values());
        if (results.length === 0) {
            return { average: 0, min: 0, max: 0, median: 0, p95: 0, total: 0, count: 0 };
        }

        const times = results.map((result) => result.executionTime).sort((a, b) => a - b);
        const total = times.reduce((sum, time) => sum + time, 0);

        return {
            average: total / times.length,
            min: times[0],
            max: times[times.length - 1],
            median: times[Math.floor(times.length / 2)],
            p95: times[Math.floor(times.length * 0.95)],
            total,
            count: times.length,
        };
    }

    /**
     * 获取任务分布统计
     */
    public getTaskDistribution(): {
        byStatus: Record<TaskStatus, number>;
        byPriority: Record<TaskPriority, number>;
        byName: Record<string, number>;
    } {
        const allTasks = [
            ...this.executor.getQueueSnapshot().pending,
            ...this.executor.getQueueSnapshot().running,
            ...Array.from(this.taskHistory.values()),
        ];

        const byStatus: Record<TaskStatus, number> = {
            [TaskStatus.PENDING]: 0,
            [TaskStatus.RUNNING]: 0,
            [TaskStatus.COMPLETED]: 0,
            [TaskStatus.FAILED]: 0,
            [TaskStatus.CANCELLED]: 0,
        };

        const byPriority: Record<TaskPriority, number> = {
            [TaskPriority.LOW]: 0,
            [TaskPriority.NORMAL]: 0,
            [TaskPriority.HIGH]: 0,
            [TaskPriority.CRITICAL]: 0,
        };

        const byName: Record<string, number> = {};

        allTasks.forEach((task) => {
            byStatus[task.status]++;
            byPriority[task.priority]++;
            byName[task.name] = (byName[task.name] || 0) + 1;
        });

        return { byStatus, byPriority, byName };
    }

    /**
     * 获取性能指标
     */
    public getPerformanceMetrics(): {
        throughput: number; // 每分钟完成的任务数
        successRate: number; // 成功率
        averageWaitTime: number; // 平均等待时间
        queueUtilization: number; // 队列利用率
    } {
        const now = Date.now();
        const oneMinuteAgo = now - 60000;

        const recentResults = Array.from(this.resultHistory.values()).filter(
            (result) => result.timestamp >= oneMinuteAgo
        );

        const recentTasks = Array.from(this.taskHistory.values()).filter(
            (task) => (task.completedAt || task.createdAt) >= oneMinuteAgo
        );

        const successfulTasks = recentTasks.filter((task) => task.status === TaskStatus.COMPLETED);
        const failedTasks = recentTasks.filter((task) => task.status === TaskStatus.FAILED);

        const totalCompleted = successfulTasks.length + failedTasks.length;

        const waitTimes = recentTasks
            .filter((task) => task.startedAt)
            .map((task) => task.startedAt! - task.createdAt);

        const averageWaitTime =
            waitTimes.length > 0
                ? waitTimes.reduce((sum, time) => sum + time, 0) / waitTimes.length
                : 0;

        const { running } = this.executor.getQueueSnapshot();
        const queueUtilization = running.length / Math.max(1, this.executor['config'].concurrency);

        return {
            throughput: recentResults.length,
            successRate: totalCompleted > 0 ? successfulTasks.length / totalCompleted : 0,
            averageWaitTime,
            queueUtilization,
        };
    }

    /**
     * 清理历史数据
     */
    public cleanupHistory(maxAge: number = 3600000): {
        tasksRemoved: number;
        resultsRemoved: number;
    } {
        const now = Date.now();
        let tasksRemoved = 0;
        let resultsRemoved = 0;

        // 清理任务历史
        for (const [taskId, task] of this.taskHistory.entries()) {
            if (now - task.createdAt > maxAge) {
                this.taskHistory.delete(taskId);
                tasksRemoved++;
            }
        }

        // 清理结果历史
        for (const [taskId, result] of this.resultHistory.entries()) {
            if (now - result.timestamp > maxAge) {
                this.resultHistory.delete(taskId);
                resultsRemoved++;
            }
        }

        // 清理按名称分组的结果
        for (const [name, results] of this.resultsByName.entries()) {
            const filteredResults = results.filter((result) => now - result.timestamp <= maxAge);
            if (filteredResults.length === 0) {
                this.resultsByName.delete(name);
            } else {
                this.resultsByName.set(name, filteredResults);
            }
        }

        return { tasksRemoved, resultsRemoved };
    }

    // 私有方法

    private handleTaskCompleted = (event: TaskEvent): void => {
        if (event.result && event.task) {
            // 保存任务历史
            this.taskHistory.set(event.task.id, event.task);

            // 保存结果
            this.resultHistory.set(event.task.id, event.result);

            // 按名称分组保存结果
            const nameResults = this.resultsByName.get(event.task.name) || [];
            nameResults.push(event.result);
            this.resultsByName.set(event.task.name, nameResults);

            // 更新统计
            this.stats.completed++;
            this.stats.totalProcessed++;
            this.updateAverageExecutionTime(event.result.executionTime);
        }
    };

    private handleTaskFailed = (event: TaskEvent): void => {
        this.taskHistory.set(event.task.id, event.task);
        this.stats.failed++;
        this.stats.totalProcessed++;
    };

    private handleTaskCancelled = (event: TaskEvent): void => {
        this.taskHistory.set(event.task.id, event.task);
        this.stats.cancelled++;
        this.stats.totalProcessed++;
    };

    private setupEventListeners(): void {
        this.executor.addEventListener('taskCompleted', this.handleTaskCompleted);
        this.executor.addEventListener('taskFailed', this.handleTaskFailed);
        this.executor.addEventListener('taskCancelled', this.handleTaskCancelled);
    }

    private matchesTaskQuery(task: Task, query: TaskQuery): boolean {
        if (query.id && task.id !== query.id) return false;
        if (query.name && task.name !== query.name) return false;
        if (query.status && task.status !== query.status) return false;
        if (query.priority && task.priority !== query.priority) return false;
        if (query.createdAfter && task.createdAt <= query.createdAfter) return false;
        if (query.createdBefore && task.createdAt >= query.createdBefore) return false;

        return true;
    }

    private matchesResultQuery<R = T>(result: TaskResult<R>, query: ResultQuery): boolean {
        if (query.taskId && result.id !== query.taskId) return false;
        if (query.taskName && result.name !== query.taskName) return false;
        if (query.executionTimeMin && result.executionTime < query.executionTimeMin) return false;
        if (query.executionTimeMax && result.executionTime > query.executionTimeMax) return false;
        if (query.timestampAfter && result.timestamp <= query.timestampAfter) return false;
        if (query.timestampBefore && result.timestamp >= query.timestampBefore) return false;

        return true;
    }

    private updateAverageExecutionTime(newTime: number): void {
        const totalTime = this.stats.averageExecutionTime * (this.stats.completed - 1) + newTime;
        this.stats.averageExecutionTime = totalTime / this.stats.completed;
    }
}
